package com.atguigu.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.constant.SystemConstant;
import com.atguigu.entity.UserAccount;
import com.atguigu.entity.UserAccountDetail;
import com.atguigu.execption.GuiguException;
import com.atguigu.mapper.UserAccountMapper;
import com.atguigu.result.ResultCodeEnum;
import com.atguigu.result.RetVal;
import com.atguigu.service.UserAccountService;
import com.atguigu.vo.AccountLockResultVo;
import com.atguigu.vo.AccountLockVo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户账户 服务实现类
 * </p>
 *
 * @author Joe
 * @since 2024-12-02
 */
@Service
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {

    @Autowired
    private UserAccountDetailServiceImpl userAccountDetailService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Transactional
    @Override
    public RetVal checkAndLock(AccountLockVo accountLockVo) {
        String checkAndLockKey="check:lock:"+accountLockVo.getOrderNo();
        String lockAccountKey="lock:account:"+accountLockVo.getOrderNo();
        //防止重复提交
        //TODO 这里时间是HOURS目的是为了打断点测试 后续调成SECONDS
        boolean isExist = redisTemplate.opsForValue().setIfAbsent(checkAndLockKey, accountLockVo.getOrderNo(), 20, TimeUnit.SECONDS);
        if(!isExist){
            //存在重复提交
            String data = redisTemplate.opsForValue().get(lockAccountKey);
            if(!StringUtils.isEmpty(data)){
                AccountLockResultVo accountLockResultVo = JSONObject.parseObject(data, AccountLockResultVo.class);
                return RetVal.ok(accountLockResultVo);
            }
            return RetVal.build(null, ResultCodeEnum.ACCOUNT_LOCK_REPEAT);
        }
        //判断账号余额是否足够 https://blog.csdn.net/qq_39220971/article/details/130245812
        UserAccount userAccount=baseMapper.checkAndLock(accountLockVo.getUserId(),accountLockVo.getAmount());
        if(userAccount==null){
            redisTemplate.delete(checkAndLockKey);
            return RetVal.build(null, ResultCodeEnum.ACCOUNT_BALANCES_NOT_ENOUGH);
        }
        //如果账号余额足够 锁定账号余额
        int rows=baseMapper.lockUserAccount(accountLockVo.getUserId(),accountLockVo.getAmount());
        if(rows==0){
            redisTemplate.delete(checkAndLockKey);
            return RetVal.build(null, ResultCodeEnum.ACCOUNT_LOCK_ERROR);
        }
        //添加账号明细
        UserAccountDetail  userAccountDetail= new UserAccountDetail();
        userAccountDetail.setUserId(accountLockVo.getUserId());
        userAccountDetail.setTitle("锁定："+accountLockVo.getContent());
        userAccountDetail.setTradeType(SystemConstant.ACCOUNT_TRADE_TYPE_LOCK);
        userAccountDetail.setAmount(accountLockVo.getAmount());
        userAccountDetail.setOrderNo("lock:"+accountLockVo.getOrderNo());
        userAccountDetailService.save(userAccountDetail);
        //返回锁定对象
        AccountLockResultVo accountLockResultVo = new AccountLockResultVo();
        accountLockResultVo.setUserId(accountLockVo.getUserId());
        accountLockResultVo.setAmount(accountLockVo.getAmount());
        accountLockResultVo.setContent(accountLockVo.getContent());
        //锁定信息放到redis里面
        //TODO 这里时间是HOURS目的是为了打断点测试 后续调成SECONDS
        redisTemplate.opsForValue().set(lockAccountKey, JSON.toJSONString(accountLockResultVo),30, TimeUnit.SECONDS);
        return RetVal.ok(accountLockResultVo);

    }

    @Override
    public void deductLockAccount(String orderNo) {
        //防止重复提交
        String deductAccountKey = "deduct:account:"+orderNo;
        String lockAccountKey = "lock:account:"+orderNo;
        //TODO 这里时间是HOURS目的是为了打断点测试 后续调成SECONDS
        boolean isExist = redisTemplate.opsForValue().setIfAbsent(deductAccountKey,orderNo,20, TimeUnit.SECONDS);
        if(!isExist){
            return;
        }
        String data = redisTemplate.opsForValue().get(lockAccountKey);
        if(!StringUtils.isEmpty(data)){
            AccountLockResultVo lockVo = JSONObject.parseObject(data, AccountLockResultVo.class);
            //解锁账户锁定金额
            int rows = baseMapper.deductLockAccount(lockVo.getUserId(),lockVo.getAmount());
            if(rows == 0){
                redisTemplate.delete(deductAccountKey);
                throw new GuiguException(ResultCodeEnum.ACCOUNT_MINUSLOCK_ERROR);
            }
            //锁定成功，添加账号明细
            UserAccountDetail userAccountDetail = new UserAccountDetail();
            userAccountDetail.setUserId(lockVo.getUserId());
            userAccountDetail.setTitle("解除锁定:"+lockVo.getContent());
            userAccountDetail.setAmount(lockVo.getAmount());
            userAccountDetail.setTradeType(SystemConstant.ACCOUNT_EXPENSE);
            userAccountDetail.setOrderNo(orderNo);
            userAccountDetailService.save(userAccountDetail);
            redisTemplate.delete(lockAccountKey);
        }
    }

    //解锁账户锁定金额与账户锁
    @Override
    public void unLockAccount(String orderNo) {
        //防止重复提交
        String unLockKey = "unlock"+orderNo;
        String lockAccountKey = "lock:account:"+orderNo;
        //TODO 这里时间是HOURS目的是为了打断点测试 后续调成SECONDS
        boolean isExist = redisTemplate.opsForValue().setIfAbsent(unLockKey,orderNo,20, TimeUnit.SECONDS);
        if(!isExist){
            return;
        }
        String data = redisTemplate.opsForValue().get(lockAccountKey);
        if(!StringUtils.isEmpty(data)){
            AccountLockResultVo lockVo = JSONObject.parseObject(data, AccountLockResultVo.class);
            //解锁锁定
            int rows = baseMapper.unLockUserAccount(lockVo.getUserId(),lockVo.getAmount());
            if(rows == 0){
                redisTemplate.delete(unLockKey);
                throw new GuiguException(ResultCodeEnum.ACCOUNT_UNLOCK_ERROR);
            }
            //锁定成功，添加账号明细
            UserAccountDetail userAccountDetail = new UserAccountDetail();
            userAccountDetail.setUserId(lockVo.getUserId());
            userAccountDetail.setTitle("解锁:"+lockVo.getContent());
            userAccountDetail.setAmount(lockVo.getAmount());
            userAccountDetail.setTradeType(SystemConstant.UNLOCK_ACCOUNT);
            userAccountDetail.setOrderNo("unlock:"+orderNo);
            userAccountDetailService.save(userAccountDetail);
            redisTemplate.delete(lockAccountKey);
        }
    }

    @Autowired
    private UserAccountMapper userAccountMapper;
    @Override
    public void addUserAccount(Long userid) {
        UserAccount userAccount = new UserAccount();
        userAccount.setUserId(userid);
        userAccount.setTotalAmount(new BigDecimal("1000"));
        userAccountMapper.insert(userAccount);
    }
}
